if(!JSON.keyToLowerCase)
{
	Date.prototype.format = function(fmt){
        var o = {
            "M+": this.getMonth()+1,
            "d+": this.getDate(),
            "H+": this.getHours(),
            "m+": this.getMinutes(),
            "s+": this.getSeconds(),
            "S+": this.getMilliseconds()
        };
        //因为date.getFullYear()出来的结果是number类型的,所以为了让结果变成字符串型，下面有两种方法：
        if(/(y+)/.test(fmt)){
            //第一种：利用字符串连接符“+”给date.getFullYear()+""，加一个空字符串便可以将number类型转换成字符串。
            fmt=fmt.replace(RegExp.$1,(this.getFullYear()+"").substr(4-RegExp.$1.length));
        }
        for(var k in o){
            if (new RegExp("(" + k +")").test(fmt)){
                //第二种：使用String()类型进行强制数据类型转换String(date.getFullYear())，这种更容易理解。
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(String(o[k]).length)));
            }
        }
        return fmt;
    };
	String.prototype.format = function(){
	    var args = arguments;
	    return this.replace(/\{\d+\}/g,function(_old,index){
	      var i = parseInt(_old.substr(1,_old.length-1));
	      if(i<args.length)
	        return args[i];
	      else
	        return _old;
	    });
	}
	JSON.keyToLowerCase = function(json){
	 	for(var key in json)
	 	{
	 		if(typeof key == "string")
	 		{
	 			if(key!=key.toLowerCase())
	 			{
	 				json[key.toLowerCase()] = json[key];
	 				delete json[key];
	 				if(typeof json[key.toLowerCase()] == "object")
	 				{
	 					JSON.keyToLowerCase(json[key.toLowerCase()])
	 				}
	 			}else if(typeof json[key] == "object")
	 				{
	 					JSON.keyToLowerCase(json[key])
	 				}
	 		}	
	 	}
	 }
	function uuid() {
		  function S4() {
		    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
		  }
		  return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
	}
	function isFireFoxOrChrome()
	{
		var ua = navigator.userAgent;
		if(!/chrome/i.test(ua)&&!/firefox/i.test(ua)&&!/safari/i.test(ua))
		{
			return false;
		}
		return true;
	}
}

function parseExercise_V1(exercises){
	var tbData = [];
	var regex = new RegExp("\\$\\{([a-z0-9A-Z]*?)\\}","g");
	var frag = new RegExp("<p>([\\s\\S]*?)</p>","g");
	var aTag = document.createElement("a");
	var data = exercises;
	if(!(exercises instanceof Array))
	{
		data = [exercises];
	}
	for(var i=0;i<data.length;i++)
	{
		var exItem = data[i];
		var mainTitle = exItem.exercise;
		var qstInfo = {thxx:[],exercise:exItem.exercise,ctime:exItem.ctime,tmdl:exItem.tmdl,tmdlName:exItem.tmdlName,funder:exItem.funder,knowledges:exItem.knowledges,purpose:exItem.purpose,id:exItem._id,level:exItem.level,answerAnalysis:exItem.answerAnalysis,detail:[]};
		var item = qstInfo.detail;
		var thxx = qstInfo.thxx;
		/// 按照<p></p>解析
		var pr = "";
		while((pr=frag.exec(mainTitle))!=null)
		{
			var sitem = {};
			sitem.title = pr[1];
			/// 解析${}
			var $r = "";
			while(($r=regex.exec(sitem.title))!=null)
			{
				!sitem.th&&(sitem.th=[]);
				sitem.th.push($r[1])
			}
			/// 创建显示用的
			aTag.innerHTML = sitem.title.replace(regex,"");
			sitem.dtitle = aTag.innerText;
			item.push(sitem);
		}
		if(item.length==0)  /// 说明没有<p/>
		{
			var sitem = {};
			sitem.title = mainTitle;
			/// 解析${}
			var $r = "";
			while(($r=regex.exec(sitem.title))!=null)
			{
				!sitem.th&&(sitem.th=[]);
				sitem.th.push($r[1])
			}
			/// 创建显示用的
			aTag.innerHTML = sitem.title.replace(regex,"");
			sitem.dtitle = aTag.innerText;
			item.push(sitem);
		}
		for(var ii=0;ii<item.length;ii++) /// 寻找题号对应的内容
		{
			var ths = item[ii].th;
			if(!ths)continue;
			for(var j=0;j<ths.length;j++)
			{
				var th = ths[j];
				for(var l=0;l<exItem.subject.length;l++)
				{
					var subject = exItem.subject[l];
					if(th==subject.th)
					{
						var thItem = {th:subject.th,tmlx:subject.tmlx,lx:subject.lx,answer:subject.lx==2?subject.answer:subject.answer[0],xsubject:subject.subject,score:subject.score[0].qzq,dscore:subject.score[0].wqzq}
						if(subject.lx==2)
							thItem.xanswer = subject.answer;
						else
							thItem.answer = subject.answer[0];
						thxx.push(thItem);
						for(var k=0;k<subject.subject.length;k++)
						{
							!item[ii].pvdAns&&(item[ii].pvdAns={});
							!item[ii].pvdAns[th]&&(item[ii].pvdAns[th]=[])
							item[ii].pvdAns[th].push(subject.subject[k].replace("#","、"));
						}
						!item[ii].answer&&(item[ii].answer="");
						item[ii].answer += "【"+subject.answer+"】 ";
					}
				}
			}
		}
		qstInfo.dtitle = item[0].dtitle;
		tbData.push(qstInfo);
	}
	if(!(exercises instanceof Array))
	{
		return tbData[0];
	}
	return tbData;
}
/// 解析章节 
/// treeData [{id,pid,nex,pre}]
function parseChapterDataForTree(treeData,excludeNotPub){
	  /// 先搞头部排序
	  treeData.sort(function(a,b){
		  if(a.pid>b.pid)
		  {
			  return 1;
		  }
		  if(a.pid==b.pid)return 0;
		  return -1;
	  })
	  /// 开始遍历
	  var len = treeData.length;
	  var pid = "-100";
	  var offset = 0;
	  var map = {};
	  var headerMap = {}; /// 没有pre的，必然是最前面的那个
	  for(var i=0;i<len;i++)
	  {
		  if(pid!=treeData[i].pid){
			  if(treeData[i].pid=="0") /// 一级
			  {
				  !treeData[i].children&&(treeData[i].children=[]);
			  }
			  map[treeData[i].id] = treeData[i];
			  if(!treeData[i].pre) /// 最开始的，包括一级和二级
				  headerMap[treeData[i].id] = {lists:[treeData[i]],nex:treeData[i].nex};
		  }
	  }
	  var root = [];
	  for(var fhd_id in headerMap)
	  {
		  var fhd = headerMap[fhd_id];
		  var hd = fhd;
		  while(hd&&hd.nex&&map[hd.nex])
		 {
			  fhd.lists.push(map[hd.nex]);
			  //hd.nex = map[hd.nex].nex;
			  hd = map[hd.nex];
		 }
		 if(fhd.lists[0].pid=="0")  /// 找到了一级的头部
		 {
			 root = fhd.lists;
		 }
	  }
	  for(var i=0;i<root.length;i++){ /// 寻找头部的父子关系
		  for(var fhd_id in headerMap)
		 {
			 var fhd = headerMap[fhd_id];
		    if(fhd.lists[0].pid == root[i].id)
		    	{
		    	   root[i].children = fhd.lists;
		    	   continue;
		    	}
		 }
	  }
	  // 排除未发布的
	  if(excludeNotPub)
	  {
		  for(var i=0;i<root.length;i++)
		  {
			  if(root[i].pubstatus!=1)
			  {
				  root.splice(i,1);
				  i--;
				  continue;
			  }
			  for(var j=0;j<root[i].children.length;j++)
			  {
				  if(root[i].children[j].pubstatus!=1)
				  {
					  j--;
					  root[i].children.splice(j,1);
				  }
			  }
		  }
	  }
	  return root;
}
function extraParse(exe){
	var items=[];
	var subs=exe.subject;
	var detail=[];
	var thxx={};
	for(var i=0;i<subs.length;i++){
		var opts=[];
		var ths=[];
		var pvdAns={};
		subs[i].subject.forEach((is)=>{
			opts.push({
				ans:is.substring(0,1),
				title:is.replace("#","、"),
				lx:parseInt(subs[i].tmlx)
			});
			pvdAns[subs[i].th]=opts;
		});
		detail.push({
			dtitle:subs[i].title.replace(/\$\{[a-zA-Z]\}/g,""),
			title:subs[i].title.replace(/\$\{[a-zA-Z]\}/g,""),
			th:[subs[i].th],
			pvdAns:pvdAns,
			answer:subs[i].answer?subs[i].answer.join(","):"",
			score:subs[i].fscore,
		});
		thxx[subs[i].th]={
			dscore:0,
			fscore:subs[i].fscore,
			hscore:subs[i].hscore,
			lx:parseInt(subs[i].tmlx),
			score:subs[i].fscore,
			stuAns:undefined,
			th:subs[i].th,
			tmlx:subs[i].tmlx,
			tname:subs[i].tname,
			xsubject:subs[i].subject,
			answer:subs[i].answer?subs[i].answer.join(","):"",
		}
	}
	return {detail:detail,thxx:thxx};
}
function parseExercise_V1v1(exercises){ /// v1 pvdAns没有解析
	var tbData = [];
	var regex = new RegExp("\\$\\{([a-z0-9A-Z]*?)\\}","g")
	var frag = new RegExp("<p>([\\s\\S]*?)</p>","g");
	var aTag = document.createElement("a");
	var data = exercises;
	if(!(exercises instanceof Array))
	{
		data = [exercises];
	}
	for(var i=0;i<data.length;i++)
	{
		var exItem = data[i];
		
		var mainTitle = exItem.exercise;
		var qstInfo = {exItem:exItem,score:exItem.score,thxx:{},exercise:exItem.exercise,ctime:exItem.ctime,tmdl:exItem.tmdl,tmdlName:exItem.tmdlName,funder:exItem.funder,knowledges:exItem.knowledges,purpose:exItem.purpose,id:exItem._id,level:exItem.level,answerAnalysis:exItem.answerAnalysis,detail:[]};
		var item = qstInfo.detail;
		var thxx = qstInfo.thxx;
		/// 按照<p></p>解析
		var pr = "";
		while((pr=frag.exec(mainTitle))!=null)
		{
			var sitem = {};
			sitem.title = pr[1];
			/// 解析${}
			var $r = "";
			while(($r=regex.exec(sitem.title))!=null)
			{
				!sitem.th&&(sitem.th=[]);
				sitem.th.push($r[1])
			}
			/// 创建显示用的
			aTag.innerHTML = sitem.title.replace(regex,"");
			sitem.dtitle = aTag.innerText;
			sitem.title = aTag.innerHTML;
			item.push(sitem);
		}
		if(item.length==0)  /// 说明没有<p/>
		{
			var sitem = {};
			sitem.title = mainTitle;
			/// 解析${}
			var $r = "";
			while(($r=regex.exec(sitem.title))!=null)
			{
				!sitem.th&&(sitem.th=[]);
				sitem.th.push($r[1])
			}
			/// 创建显示用的
			aTag.innerHTML = sitem.title.replace(regex,"");
			sitem.dtitle = aTag.innerText;
			sitem.title = aTag.innerHTML;
			item.push(sitem);
		}
		for(var ii=0;ii<item.length;ii++) /// 寻找题号对应的内容
		{
			var ths = item[ii].th;
			if(!ths)continue;
			for(var j=0;j<ths.length;j++)
			{
				var th = ths[j];
				for(var l=0;l<exItem.subject.length;l++) /// 注意，可能没有设置
				{
					var subject = exItem.subject[l];
					if(th==subject.th)
					{
						var o_score = subject.score[0];
						var thItem = {stuAns:subject.stuAns,fscore:o_score.qzq,hscore:o_score.wqzq,th:subject.th,tname:subject.tname,tmlx:subject.tmlx,lx:subject.lx,xsubject:subject.subject,score:subject.score[0].qzq,dscore:subject.score[0].wqzq}
						if(subject.answer)
						{
							thItem.answer = subject.lx==2?subject.answer:subject.answer[0]
						}
						//if(subject.lx==2)
							//thItem.xanswer = subject.answer;
						//else
							//thItem.answer = subject.answer[0];
						//thxx.push(thItem);
						thxx[th+""] = thItem;
						for(var k=0;k<subject.subject.length;k++)
						{
							!item[ii].pvdAns&&(item[ii].pvdAns={});
							!item[ii].pvdAns[th]&&(item[ii].pvdAns[th]=[])
							var tmxx =  subject.subject[k].split("#")[0];
							item[ii].pvdAns[th].push({ans:tmxx,title:subject.subject[k].replace("#","、"),lx:subject.lx});
						}
						if(subject.answer)
						{
							!item[ii].answer&&(item[ii].answer="");
							item[ii].answer += (subject.answer+" ");
						}
						item[ii].score=subject.fscore;
					}
				}
			}
		}
		qstInfo.dtitle = item[0].dtitle;
		if(exItem.subject.length>1 && exItem.exercise.match(regex).length==1){		// 只有一个占位符但是有小题的情况
			var etr= extraParse(exItem);
			qstInfo.detail=etr.detail;
			qstInfo.thxx=etr.thxx;
			qstInfo.mainTg=qstInfo.exercise.replace(/\$\{[a-zA-Z0-9]\}/,"");
		}
		tbData.push(qstInfo);
	}
	if(!(exercises instanceof Array))
	{
		return tbData[0];
	}
	return tbData;
}

/**
 * Vue input限制只能输入正整数（可控制最小最大值）
 * 例子：<input type="text" v-integer="{min:1, max:10}">
 */
Vue.directive('integer', {
	bind: function(el, binding) {
    let attr = binding.value; //传入的参数
    el.handler = function() {
    		var val = el.value;
    	  	if(isNaN(val))
    	  	{
    	  		val = val.replace(/\D+/, '');
    	  	}
    	  	attr.max !== undefined ? val > attr.max ? (val = attr.max) : null : null;
    	  	attr.min !== undefined ? (val < attr.min ? (val = attr.min) : null) : null;
    	  	if(val!==el.value)
    	  	{
    	  		el.value = val;
    	  		el.dispatchEvent(new Event('input'));
    	  	}
    };
    el.addEventListener('input', el.handler);
  },
  unbind: function(el) {
    el.removeEventListener('input', el.handler);
  }
});
if(axios)
{
	axios.interceptors.response.use(function (response) {
		if(typeof response.data =="object")
		{
			if(response.data.code==401)
			{
				window.location = _AppRootContext;
			}
		}
	    return response;
	  }, function (error) {
	    
	  });
	axios.defaults.headers["Content-Type"] = "application/x-www-form-urlencoded";
	axios.defaults.transformRequest = function(data,headers){
		if(FormData&& data instanceof FormData)
		{
			return data;
		}
		if(typeof data == "object")
		{
			if(data instanceof Array)
			{
				return data;
			}
			else
			{
				var params;
				for(var key in data)
				{
					params = (params?"{2}&{0}={1}":"{0}={1}").format(key,data[key],params);
				}
				return params;
			}
		}
		return data;
	};
}

/**
 * 上传
 */
Vue.component("ws-vue-upload",{
	name:'ws-vue-upload',
	props:["option"],
	data:function(){
		return {
			fileName:'',
			process:0,
			formData:''
		};
	},
	methods:{
		change:function(e){
			console.log(e);
		},
		getFile:function(){
			return this.$refs.element;
		},
		cancel:function(e){
			this.fileName = "";
		},
		uploading:function(){
			var shardingSize = 2097152;
			if(this.option.sharding){ ///分片
				shardingSize = this.option.shardingSize||2097152;
			}
			function upload(file,index,params)
			{
				if(!this.option.sharding)
				{
					shardingSize = file.size+1000;
				}
				var self = this;
				var formData = new FormData();//初始化一个FormData对象
		        var nextSize = Math.min((index + 1) * shardingSize, file.size);//读取到结束位置
		        var last = false;
		        var fileData = file.slice(index * shardingSize, nextSize);//截取 部分文件 块
		        if(fileData.size<=0)
		        {
			        	if(this.option.onComplete){
            	 			this.option.onComplete();
            	 		}
		        		return;
		        }
		        formData.append(this.option.fileName||"file", fileData);//将 部分文件 塞入FormData
		        formData.append("offset",index);
		        if (file.size <= nextSize) {//如果上传完成，则跳出继续上传
			         formData.append("last",last);
                     last = true;
                 }
		        for(var key in this.option.params)
		        	{
		        		formData.append(key,params[key]);
		        	}
		        axios({
		        	 method: "post",
		             url: this.option.url,
		             data: formData,
		             headers:{'Content-Type':'false',"processData": "false"}
		            })
		         .then(function (response) {
	        	 		self.process = ((index*shardingSize)+fileData.size)*100/file.size;
		        	 	if(self.option.onResponseData){
		        	 		if(self.option.onResponseData(response,self)==false)return;
		        	 	}
		        	 	if(response.data.data.offset)
		        	 	{
		        	 		console.log("开始断点续传");
		        	 		index = response.data.data.offset;// -1;
		        	 		if(index<0)
		        	 		{
		        	 			index=0;
		        	 		}
		        	 	} 
		            if(self.process != 100)
		            	{
		            		upload.call(self,file,++index,params);//递归调用
		            	}
		            else{
	            	 		if(self.option.onComplete){
	            	 			self.option.onComplete(response,self);
	            	 		}
	                 }
				  })
				.catch(function (error) {
					 console.log(error);
					 self.$msgBox.error("发生异常");
				  });
			}
			upload.call(this,this.$refs.element.files[0],0,this.option.params);
		},
		onDelete:function(){
			if(this.option.onDelete)
			{
				this.option.onDelete();
			}
		}
	},
	template:'<div class="ws-vue-upload"> \
				<input type="file" ref="element" @change="fileName=$event.target.value"/> \
				<div class="ws-vue-upload-box"> \
					<div @click="$refs.element.click()"><div class="ws-vue-upload-process" :style="{width:(process||0)+\'%\'}"></div><span>{{fileName}}</span></div> \
					<a class="btn btn-sm btn-primary" v-if="fileName.length==0" @click="$refs.element.click()"> <i class="fa fa-upload"></i> 选择文件 </a>\
					<a class="btn btn-sm btn-warning" v-if="fileName.length>0&&process!=100" @click="uploading"> <i class="fa fa-upload"></i> 上传文件 </a> \
					<a class="btn btn-sm btn-danger" v-if="fileName.length>0&&process!=100" @click="cancel"> <i class="fa fa-close"></i> 取消 </a> \
					<a class="btn btn-sm btn-primary" v-if="fileName.length>0&&process==100&&!option.onDelete" > <i class="fa fa-check"></i> 完成 </a> \
					<a class="btn btn-sm btn-danger" v-if="fileName.length>0&&process==100&&option.onDelete" @click="cancel"> <i class="fa fa-trash"></i> 删除 </a> \
				</div> \
			</div>'
});